PDB: watchpoints for process context
authorach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>
Mon, 15 Aug 2005 19:04:28 +0000 (19:04 +0000)
committerach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>
Mon, 15 Aug 2005 19:04:28 +0000 (19:04 +0000)
15 files changed:
tools/debugger/pdb/Domain.ml
tools/debugger/pdb/Domain.mli
tools/debugger/pdb/Makefile
tools/debugger/pdb/PDB.ml
tools/debugger/pdb/Process.ml
tools/debugger/pdb/Process.mli
tools/debugger/pdb/debugger.ml
tools/debugger/pdb/linux-2.6-module/debug.c
tools/debugger/pdb/linux-2.6-module/module.c
tools/debugger/pdb/linux-2.6-module/pdb_debug.h
tools/debugger/pdb/linux-2.6-module/pdb_module.h
tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
tools/debugger/pdb/pdb_caml_domain.c
tools/debugger/pdb/pdb_caml_process.c
tools/debugger/pdb/readme

index 29754b47f86bc6da106d3b936a53cb0e5f1c8212..dc3fd2fb30c34dc03fb7ce35f60fac6681062f67 100644 (file)
@@ -36,6 +36,7 @@ let string_of_context ctx =
       Printf.sprintf "{domain} domain: %d, vcpu: %d"
                       ctx.domain  ctx.vcpu
 
+external read_register : context_t -> int -> int32 = "dom_read_register"
 external read_registers : context_t -> registers = "dom_read_registers"
 external write_register : context_t -> register -> int32 -> unit =
   "dom_write_register"
index f9c92a30f59d046b38fb615a27d508c2d62e00b7..d9cf115c4f8afb9f4e37bb775cf3e7a871f98f7d 100644 (file)
@@ -22,6 +22,7 @@ val get_vcpu : context_t -> int
 
 val string_of_context : context_t -> string
 
+val read_register : context_t -> int -> int32
 val read_registers : context_t -> registers
 val write_register : context_t -> register -> int32 -> unit
 val read_memory : context_t -> int32 -> int -> int list
index 9652a110133f4f2230e2c8614cbee5f09a61cf16..85f8beaff7deed94e99d1267c590668d66c3f234 100644 (file)
@@ -33,7 +33,8 @@ LIBDIRS    += ../libxendebug
 LIBS       += unix str
 
 # bc = byte-code, dc = debug byte-code
-all : patches dc
+# patches = patch linux domU source code
+all : dc
 
 SOURCES    += pdb_caml_xc.c 
 SOURCES    += pdb_caml_domain.c pdb_caml_process.c
index 3c4b06336211aabc378a334b0ddf3d87def01c30..da9ad7d2c685f2633d69c370355409bd6b93d667 100644 (file)
@@ -219,6 +219,17 @@ let add_default_context sock =
 
 (***************************************************************************)
 
+let read_register ctx register =    (* register is int32 because of sscanf *)
+  match ctx with
+  | Void -> 0l                                      (* default for startup *)
+  | Domain d  -> Domain.read_register d register
+  | Process p ->
+      begin
+       Process.read_register p register;
+       raise No_reply
+      end
+  | _ -> raise (Unimplemented "read registers")
+
 let read_registers ctx =
   match ctx with
   | Void -> Intel.null_registers                    (* default for startup *)
@@ -278,15 +289,43 @@ let step ctx =
 let insert_memory_breakpoint ctx addr len =
   match ctx with
   | Domain d  -> Domain.insert_memory_breakpoint d addr len
-  | Process p  -> Process.insert_memory_breakpoint p addr len
+  | Process p  ->
+      begin
+       Process.insert_memory_breakpoint p addr len;
+       raise No_reply
+      end
   | _ -> raise (Unimplemented "insert memory breakpoint")
 
 let remove_memory_breakpoint ctx addr len =
   match ctx with
   | Domain d  -> Domain.remove_memory_breakpoint d addr len
-  | Process p  -> Process.remove_memory_breakpoint p addr len
+  | Process p  ->
+      begin
+       Process.remove_memory_breakpoint p addr len;
+       raise No_reply
+      end
   | _ -> raise (Unimplemented "remove memory breakpoint")
 
+let insert_watchpoint ctx kind addr len =
+  match ctx with
+(*  | Domain d  -> Domain.insert_watchpoint d kind addr len  TODO *)
+  | Process p  ->
+      begin
+       Process.insert_watchpoint p kind addr len;
+       raise No_reply
+      end
+  | _ -> raise (Unimplemented "insert watchpoint")
+
+let remove_watchpoint ctx kind addr len =
+  match ctx with
+(*  | Domain d  -> Domain.remove_watchpoint d kind addr len  TODO *)
+  | Process p  ->
+      begin
+       Process.remove_watchpoint p kind addr len;
+       raise No_reply
+      end
+  | _ -> raise (Unimplemented "remove watchpoint")
+
 
 let pause ctx =
   match ctx with
index 5585da0c5c737bdf94ae0390bb84a4bb14213bca..ad98241de4b53c668889974be819fda9bd9c6268 100644 (file)
@@ -54,6 +54,7 @@ let attach_debugger proc_ctx dom_ctx =
   proc_ctx.ring   <- Xen_domain.get_ring   dom_ctx;
   _attach_debugger proc_ctx
 
+external read_register : context_t -> int -> unit = "proc_read_register"
 external read_registers : context_t -> unit = "proc_read_registers"
 external write_register : context_t -> register -> int32 -> unit =
   "proc_write_register"
@@ -69,6 +70,10 @@ external insert_memory_breakpoint : context_t -> int32 -> int -> unit =
   "proc_insert_memory_breakpoint"
 external remove_memory_breakpoint : context_t -> int32 -> int -> unit = 
   "proc_remove_memory_breakpoint"
+external insert_watchpoint : context_t -> int -> int32 -> int -> unit =
+  "proc_insert_watchpoint"
+external remove_watchpoint : context_t -> int -> int32 -> int -> unit =
+  "proc_remove_watchpoint"
 
 let pause ctx =
   pause_target ctx
index ed5b8bfe87bf936eae11998009033fc31d74aea5..733b681f599abfa30862ed5506ae7071bace4746 100644 (file)
@@ -26,7 +26,7 @@ val attach_debugger : context_t -> Xen_domain.context_t -> unit
 val detach_debugger : context_t -> unit
 val pause : context_t -> unit
 
-
+val read_register : context_t -> int -> unit
 val read_registers : context_t -> unit
 val write_register : context_t -> register -> int32 -> unit
 val read_memory : context_t -> int32 -> int -> unit
@@ -37,3 +37,5 @@ val step : context_t -> unit
 
 val insert_memory_breakpoint : context_t -> int32 -> int -> unit
 val remove_memory_breakpoint : context_t -> int32 -> int -> unit
+val insert_watchpoint : context_t -> int -> int32 -> int -> unit
+val remove_watchpoint : context_t -> int -> int32 -> int -> unit
index 6d20b682941fa625cde71290e2459ed98a921ff4..aa741a456678c624e4586f24b82f0ef59668d481 100644 (file)
@@ -53,10 +53,20 @@ let gdb_step ctx =
   PDB.step ctx;
   raise No_reply
 
+(**
+   Read Register Command.
+   return register as a 4-byte value.
+ *)
+let gdb_read_register ctx command =
+  let read_reg register =
+    (Printf.sprintf "%08lx" (Util.flip_int32 (PDB.read_register ctx register)))
+  in
+  Scanf.sscanf command "p%x" read_reg
+    
 
 (**
    Read Registers Command.
-   returns 16 4-byte registers in a particular defined by gdb.
+   returns 16 4-byte registers in a particular format defined by gdb.
  *)
 let gdb_read_registers ctx =
   let regs = PDB.read_registers ctx in
@@ -100,7 +110,7 @@ let gdb_read_memory ctx command =
     with
       Failure s -> "E02"
   in
-  Scanf.sscanf command "m%lx,%d" read_mem
+  Scanf.sscanf command "m%lx,%x" read_mem
 
 
 
@@ -218,16 +228,24 @@ let pdb_extensions command sock =
 (**
    Insert Breakpoint or Watchpoint Packet
  *)
+
+let bwc_watch_write  = 102                              (* from pdb_module.h *)
+let bwc_watch_read   = 103
+let bwc_watch_access = 104
+
 let gdb_insert_bwcpoint ctx command =
   let insert cmd addr length =
     try
       match cmd with
       | 0 -> PDB.insert_memory_breakpoint ctx addr length; "OK"
+      | 2 -> PDB.insert_watchpoint ctx bwc_watch_write  addr length; "OK"
+      | 3 -> PDB.insert_watchpoint ctx bwc_watch_read   addr length; "OK"
+      | 4 -> PDB.insert_watchpoint ctx bwc_watch_access addr length; "OK"
       | _ -> ""
     with
       Failure s -> "E03"
   in
-  Scanf.sscanf command "Z%d,%lx,%d" insert
+  Scanf.sscanf command "Z%d,%lx,%x" insert
 
 (**
    Remove Breakpoint or Watchpoint Packet
@@ -237,6 +255,9 @@ let gdb_remove_bwcpoint ctx command =
     try
       match cmd with
       | 0 -> PDB.remove_memory_breakpoint ctx addr length; "OK"
+      | 2 -> PDB.remove_watchpoint ctx bwc_watch_write  addr length; "OK"
+      | 3 -> PDB.remove_watchpoint ctx bwc_watch_read   addr length; "OK"
+      | 4 -> PDB.remove_watchpoint ctx bwc_watch_access addr length; "OK"
       | _ -> ""
     with
       Failure s -> "E04"
@@ -260,6 +281,7 @@ let process_command command sock =
     | 'k' -> gdb_kill ()
     | 'm' -> gdb_read_memory ctx command
     | 'M' -> gdb_write_memory ctx command
+    | 'p' -> gdb_read_register ctx command
     | 'P' -> gdb_write_register ctx command
     | 'q' -> gdb_query command
     | 's' -> gdb_step ctx
@@ -270,7 +292,7 @@ let process_command command sock =
     | 'Z' -> gdb_insert_bwcpoint ctx command
     | _ -> 
        print_endline (Printf.sprintf "unknown gdb command [%s]" command);
-       "E02"
+       ""
   with
     Unimplemented s ->
       print_endline (Printf.sprintf "loser. unimplemented command [%s][%s]" 
index 983e02dcccb628413b6225a510bcd6d81074231f..ae1064ebad8666cc690f241f17fb70b292707c42 100644 (file)
 #include <asm-i386/kdebug.h>
 #include <asm-xen/asm-i386/processor.h>
 #include <asm-xen/asm-i386/ptrace.h>
+#include <asm-xen/asm-i386/tlbflush.h>
 #include <asm-xen/xen-public/xen.h>
 #include "pdb_module.h"
 #include "pdb_debug.h"
 
-#define BWC_DEBUG 1
-#define BWC_INT3  3
+
+static int pdb_debug_fn (struct pt_regs *regs, long error_code,
+                         unsigned int condition);
+static int pdb_int3_fn (struct pt_regs *regs, long error_code);
+static int pdb_page_fault_fn (struct pt_regs *regs, long error_code,
+                              unsigned int condition);
+
+/***********************************************************************/
+
 typedef struct bwcpoint                           /* break/watch/catch point */
 {
     struct list_head list;
     memory_t address;
-    u32 domain;
-    u32 process;
-    u8  old_value;                            /* old value for software bkpt */
+    int length;
+
     u8  type;                                                     /* BWC_??? */
+    u8  mode;                   /* for BWC_PAGE, the current protection mode */
+    u32 process;
+    u8  error;                /* error occured when enabling: don't disable. */
+
+    /* original values */
+    u8    orig_bkpt;                               /* single byte breakpoint */
+    pte_t orig_pte;
+
+    struct list_head watchpt_read_list;     /* read watchpoints on this page */
+    struct list_head watchpt_write_list;                            /* write */
+    struct list_head watchpt_access_list;                          /* access */
+    struct list_head watchpt_disabled_list;                      /* disabled */
+
+    struct bwcpoint *parent;             /* watchpoint: bwc_watch (the page) */
+    struct bwcpoint *watchpoint;      /* bwc_watch_step: original watchpoint */
 } bwcpoint_t, *bwcpoint_p;
 
-static bwcpoint_t bwcpoint_list;
+static struct list_head bwcpoint_list = LIST_HEAD_INIT(bwcpoint_list);
+
+#define _pdb_bwcpoint_alloc(_var) \
+{ \
+    if ( (_var = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL)) == NULL ) \
+        printk("error: unable to allocate memory %d\n", __LINE__); \
+    else { \
+        memset(_var, 0, sizeof(bwcpoint_t)); \
+        INIT_LIST_HEAD(&_var->watchpt_read_list); \
+        INIT_LIST_HEAD(&_var->watchpt_write_list); \
+        INIT_LIST_HEAD(&_var->watchpt_access_list); \
+        INIT_LIST_HEAD(&_var->watchpt_disabled_list); \
+    } \
+}
+
+/***********************************************************************/
+
+static void _pdb_bwc_print_list (struct list_head *, char *, int);
+
+static void
+_pdb_bwc_print (bwcpoint_p bwc, char *label, int level)
+{
+    printk("%s%03d 0x%08lx:0x%02x %c\n", label, bwc->type,
+           bwc->address, bwc->length, bwc->error ? 'e' : '-');
+
+    if ( !list_empty(&bwc->watchpt_read_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_read_list, "r", level);
+    if ( !list_empty(&bwc->watchpt_write_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_write_list, "w", level);
+    if ( !list_empty(&bwc->watchpt_access_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_access_list, "a", level);
+    if ( !list_empty(&bwc->watchpt_disabled_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_disabled_list, "d", level);
+}
+
+static void
+_pdb_bwc_print_list (struct list_head *bwc_list, char *label, int level)
+{
+    struct list_head *ptr;
+    int counter = 0;
+
+    list_for_each(ptr, bwc_list)
+    {
+        bwcpoint_p bwc = list_entry(ptr, bwcpoint_t, list);
+        printk("  %s[%02d]%s ", level > 0 ? "  " : "", counter++,
+                                level > 0 ? "" : "  ");
+        _pdb_bwc_print(bwc, label, level+1);
+    }
+
+    if (counter == 0)
+    {
+        printk("  empty list\n");
+    }
+}
 
 void
-pdb_initialize_bwcpoint (void)
+pdb_bwc_print_list (void)
+{
+    _pdb_bwc_print_list(&bwcpoint_list, " ", 0);
+}
+
+bwcpoint_p
+pdb_search_watchpoint (u32 process, memory_t address)
 {
-    memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
-    INIT_LIST_HEAD(&bwcpoint_list.list);
+    bwcpoint_p bwc_watch = (bwcpoint_p) 0;
+    bwcpoint_p bwc_entry = (bwcpoint_p) 0;
+    struct list_head *ptr;
 
-    return;
+    list_for_each(ptr, &bwcpoint_list)                /* find bwc page entry */
+    {
+        bwc_watch = list_entry(ptr, bwcpoint_t, list);
+        if (bwc_watch->address == (address & PAGE_MASK)) break;
+    }
+
+    if ( !bwc_watch )
+    {
+        return (bwcpoint_p) 0;
+    }
+
+#define __pdb_search_watchpoint_list(__list) \
+    list_for_each(ptr, (__list))  \
+    { \
+        bwc_entry = list_entry(ptr, bwcpoint_t, list); \
+        if ( bwc_entry->process == process &&          \
+             bwc_entry->address <= address &&          \
+             bwc_entry->address + bwc_entry->length > address ) \
+            return bwc_entry; \
+    }
+
+    __pdb_search_watchpoint_list(&bwc_watch->watchpt_read_list);
+    __pdb_search_watchpoint_list(&bwc_watch->watchpt_write_list);
+    __pdb_search_watchpoint_list(&bwc_watch->watchpt_access_list);
+
+#undef __pdb_search_watchpoint_list
+
+    return (bwcpoint_p) 0;
 }
 
+/*************************************************************/
 
 int
 pdb_suspend (struct task_struct *target)
@@ -136,6 +246,35 @@ _pdb_set_register (struct task_struct *target, int reg, unsigned long val)
     return;
 }
 
+int
+pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op)
+{
+    int rc = 0;
+
+    switch (op->reg)
+    {
+    case  0: op->value = _pdb_get_register(target, LINUX_EAX); break;
+    case  1: op->value = _pdb_get_register(target, LINUX_ECX); break;
+    case  2: op->value = _pdb_get_register(target, LINUX_EDX); break;
+    case  3: op->value = _pdb_get_register(target, LINUX_EBX); break;
+    case  4: op->value = _pdb_get_register(target, LINUX_ESP); break;
+    case  5: op->value = _pdb_get_register(target, LINUX_EBP); break;
+    case  6: op->value = _pdb_get_register(target, LINUX_ESI); break;
+    case  7: op->value = _pdb_get_register(target, LINUX_EDI); break;
+    case  8: op->value = _pdb_get_register(target, LINUX_EIP); break;
+    case  9: op->value = _pdb_get_register(target, LINUX_EFL); break;
+
+    case 10: op->value = _pdb_get_register(target, LINUX_CS); break;
+    case 11: op->value = _pdb_get_register(target, LINUX_SS); break;
+    case 12: op->value = _pdb_get_register(target, LINUX_DS); break;
+    case 13: op->value = _pdb_get_register(target, LINUX_ES); break;
+    case 14: op->value = _pdb_get_register(target, LINUX_FS); break;
+    case 15: op->value = _pdb_get_register(target, LINUX_GS); break;
+    }
+
+    return rc;
+}
+
 int
 pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op)
 {
@@ -209,18 +348,14 @@ pdb_step (struct task_struct *target)
     eflags |= X86_EFLAGS_TF;
     _pdb_set_register(target, LINUX_EFL, eflags);
 
-    bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
-    if ( bkpt == NULL )
-    {
-        printk("error: unable to allocation memory\n");
-        return -1;
-    }
+    _pdb_bwcpoint_alloc(bkpt);
+    if ( bkpt == NULL )  return -1;
 
     bkpt->process = target->pid;
     bkpt->address = 0;
     bkpt->type    = BWC_DEBUG;
     
-    list_add(&bkpt->list, &bwcpoint_list.list);
+    list_add_tail(&bkpt->list, &bwcpoint_list);
 
     wake_up_process(target);
 
@@ -237,31 +372,27 @@ pdb_insert_memory_breakpoint (struct task_struct *target,
 
     printk("insert breakpoint %d:%lx len: %d\n", target->pid, address, length);
 
-    bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
-    if ( bkpt == NULL )
-    {
-        printk("error: unable to allocation memory\n");
-        return -1;
-    }
-
     if ( length != 1 )
     {
         printk("error: breakpoint length should be 1\n");
-        kfree(bkpt);
         return -1;
     }
 
+    _pdb_bwcpoint_alloc(bkpt);
+    if ( bkpt == NULL ) return -1;
+
     bkpt->process = target->pid;
     bkpt->address = address;
     bkpt->type    = BWC_INT3;
 
-    pdb_access_memory(target, address, &bkpt->old_value, 1, 0);
-    pdb_access_memory(target, address, &breakpoint_opcode, 1, 1);
+    pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_READ);
+    pdb_access_memory(target, address, &breakpoint_opcode, 1, PDB_MEM_WRITE);
     
-    list_add(&bkpt->list, &bwcpoint_list.list);
+    list_add_tail(&bkpt->list, &bwcpoint_list);
 
     printk("breakpoint_set %d:%lx  OLD: 0x%x\n",
-           target->pid, address, bkpt->old_value);
+           target->pid, address, bkpt->orig_bkpt);
+    pdb_bwc_print_list();
 
     return rc;
 }
@@ -276,7 +407,7 @@ pdb_remove_memory_breakpoint (struct task_struct *target,
     printk ("remove breakpoint %d:%lx\n", target->pid, address);
 
     struct list_head *entry;
-    list_for_each(entry, &bwcpoint_list.list)
+    list_for_each(entry, &bwcpoint_list)
     {
         bkpt = list_entry(entry, bwcpoint_t, list);
         if ( target->pid == bkpt->process && 
@@ -285,17 +416,223 @@ pdb_remove_memory_breakpoint (struct task_struct *target,
             break;
     }
     
-    if (bkpt == &bwcpoint_list || bkpt == NULL)
+    if (entry == &bwcpoint_list)
     {
         printk ("error: no breakpoint found\n");
         return -1;
     }
 
+    pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_WRITE);
+
     list_del(&bkpt->list);
+    kfree(bkpt);
 
-    pdb_access_memory(target, address, &bkpt->old_value, 1, 1);
+    pdb_bwc_print_list();
 
-    kfree(bkpt);
+    return rc;
+}
+
+#define PDB_PTE_UPDATE   1
+#define PDB_PTE_RESTORE  2
+
+int
+pdb_change_pte (struct task_struct *target, bwcpoint_p bwc, int mode)
+{
+    int rc = 0;
+    pgd_t *pgd;
+    pud_t *pud;
+    pmd_t *pmd;
+    pte_t *ptep;
+
+    pgd = pgd_offset(target->mm, bwc->address);
+    if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))  return -1;
+
+    pud = pud_offset(pgd, bwc->address);
+    if (pud_none(*pud) || unlikely(pud_bad(*pud))) return -2;
+
+    pmd = pmd_offset(pud, bwc->address);
+    if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) return -3;
+
+    ptep = pte_offset_map(pmd, bwc->address);
+    if (!ptep)  return -4;
+
+    switch ( mode )
+    {
+    case PDB_PTE_UPDATE:      /* added or removed a watchpoint.  update pte. */
+    {
+        pte_t new_pte;
+
+        if ( pte_val(bwc->parent->orig_pte) == 0 )    /* new watchpoint page */
+        {
+            bwc->parent->orig_pte = *ptep;
+        }
+
+        new_pte = bwc->parent->orig_pte;
+
+        if ( !list_empty(&bwc->parent->watchpt_read_list)  || 
+             !list_empty(&bwc->parent->watchpt_access_list) )
+        {
+            new_pte = pte_rdprotect(new_pte);
+        }
+
+        if ( !list_empty(&bwc->parent->watchpt_write_list) ||
+             !list_empty(&bwc->parent->watchpt_access_list) )
+        {
+            new_pte = pte_wrprotect(new_pte);
+        }
+        
+        if ( pte_val(new_pte) != pte_val(*ptep) )
+        {
+            *ptep = new_pte;
+            flush_tlb_mm(target->mm);
+        }
+        break;
+    }
+    case PDB_PTE_RESTORE :   /* suspend watchpoint by restoring original pte */
+    {
+        *ptep = bwc->parent->orig_pte;
+        flush_tlb_mm(target->mm);
+        break;
+    }
+    default :
+    {
+        printk("(linux) unknown mode %d %d\n", mode, __LINE__);
+        break;
+    }
+    }
+
+    pte_unmap(ptep);                /* can i flush the tlb before pte_unmap? */
+
+    return rc;
+}
+
+int
+pdb_insert_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
+{
+    int rc = 0;
+
+    bwcpoint_p bwc_watch;
+    bwcpoint_p bwc_entry;
+    struct list_head *ptr;
+    unsigned long page = watchpt->address & PAGE_MASK;
+    struct list_head *watchpoint_list;
+    
+    printk("insert watchpoint: %d %x %x\n", 
+           watchpt->type, watchpt->address, watchpt->length);
+
+    list_for_each(ptr, &bwcpoint_list) /* find existing bwc page entry */
+    {
+        bwc_watch = list_entry(ptr, bwcpoint_t, list);
+
+        if (bwc_watch->address == page)  goto got_bwc_watch;
+    }
+
+    _pdb_bwcpoint_alloc(bwc_watch);                  /* create new bwc:watch */
+    if ( bwc_watch == NULL ) return -1;
+
+    bwc_watch->type    = BWC_WATCH;
+    bwc_watch->process = target->pid;
+    bwc_watch->address = page;
+
+    list_add_tail(&bwc_watch->list, &bwcpoint_list);
+
+ got_bwc_watch:
+
+    switch (watchpt->type)
+    {
+    case BWC_WATCH_READ:
+        watchpoint_list = &bwc_watch->watchpt_read_list; break;
+    case BWC_WATCH_WRITE: 
+        watchpoint_list = &bwc_watch->watchpt_write_list; break;
+    case BWC_WATCH_ACCESS:
+        watchpoint_list = &bwc_watch->watchpt_access_list; break;
+    default:
+        printk("unknown type %d\n", watchpt->type); return -2;
+    }
+
+    _pdb_bwcpoint_alloc(bwc_entry);                  /* create new bwc:entry */
+    if ( bwc_entry == NULL ) return -1;
+
+    bwc_entry->process = target->pid;
+    bwc_entry->address = watchpt->address;
+    bwc_entry->length  = watchpt->length;
+    bwc_entry->type    = watchpt->type;
+    bwc_entry->parent  = bwc_watch;
+
+    list_add_tail(&bwc_entry->list, watchpoint_list);
+    pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
+
+    pdb_bwc_print_list();
+
+    return rc;
+}
+
+int 
+pdb_remove_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
+{
+    int rc = 0;
+    bwcpoint_p bwc_watch = (bwcpoint_p) NULL;
+    bwcpoint_p bwc_entry = (bwcpoint_p) NULL;
+    unsigned long page = watchpt->address & PAGE_MASK;
+    struct list_head *ptr;
+    struct list_head *watchpoint_list;
+
+    printk("remove watchpoint: %d %x %x\n", 
+           watchpt->type, watchpt->address, watchpt->length);
+
+    list_for_each(ptr, &bwcpoint_list)                /* find bwc page entry */
+    {
+        bwc_watch = list_entry(ptr, bwcpoint_t, list);
+        if (bwc_watch->address == page) break;
+    }
+
+    if ( !bwc_watch )
+    {
+        printk("(linux) delete watchpoint: can't find bwc page 0x%08x\n",
+               watchpt->address);
+        return -1;
+    }
+
+    switch (watchpt->type)
+    {
+    case BWC_WATCH_READ:
+        watchpoint_list = &bwc_watch->watchpt_read_list; break;
+    case BWC_WATCH_WRITE:
+        watchpoint_list = &bwc_watch->watchpt_write_list; break;
+    case BWC_WATCH_ACCESS:
+        watchpoint_list = &bwc_watch->watchpt_access_list; break;
+    default:
+        printk("unknown type %d\n", watchpt->type); return -2;
+    }
+
+    list_for_each(ptr, watchpoint_list)                   /* find watchpoint */
+    {
+        bwc_entry = list_entry(ptr, bwcpoint_t, list);
+        if ( bwc_entry->address == watchpt->address &&
+             bwc_entry->length  == watchpt->length ) break;
+    }
+
+    if ( !bwc_entry )                           /* or ptr == watchpoint_list */
+    {
+        printk("(linux) delete watchpoint: can't find watchpoint 0x%08x\n",
+               watchpt->address);
+        return -1;
+    }
+    
+    list_del(&bwc_entry->list);
+    pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
+    kfree(bwc_entry);
+
+
+    if ( list_empty(&bwc_watch->watchpt_read_list)  &&
+         list_empty(&bwc_watch->watchpt_write_list) &&
+         list_empty(&bwc_watch->watchpt_access_list) )
+    {
+        list_del(&bwc_watch->list);
+        kfree(bwc_watch);
+    }
+
+    pdb_bwc_print_list();
 
     return rc;
 }
@@ -312,16 +649,24 @@ pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
        switch (val) 
     {
        case DIE_DEBUG:
-               if (pdb_debug_fn(args->regs, args->trapnr, args->err))
+               if ( pdb_debug_fn(args->regs, args->trapnr, args->err) )
                        return NOTIFY_STOP;
                break;
     case DIE_TRAP:
-               if (args->trapnr == 3 && pdb_int3_fn(args->regs, args->err))
+               if ( args->trapnr == 3 && pdb_int3_fn(args->regs, args->err) )
                        return NOTIFY_STOP;
         break;
        case DIE_INT3:          /* without kprobes, we should never see DIE_INT3 */
-       case DIE_GPF:
+               if ( pdb_int3_fn(args->regs, args->err) )
+                       return NOTIFY_STOP;
+               break;
        case DIE_PAGE_FAULT:
+               if ( pdb_page_fault_fn(args->regs, args->trapnr, args->err) )
+                       return NOTIFY_STOP;
+               break;
+       case DIE_GPF:
+        printk("---------------GPF\n");
+        break;
        default:
                break;
        }
@@ -330,70 +675,110 @@ pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
 }
 
 
-int
+static int
 pdb_debug_fn (struct pt_regs *regs, long error_code, 
                    unsigned int condition)
 {
     pdb_response_t resp;
     bwcpoint_p bkpt = NULL;
-
     struct list_head *entry;
-    list_for_each(entry, &bwcpoint_list.list)
+
+    printk("pdb_debug_fn\n");
+
+    list_for_each(entry, &bwcpoint_list)
     {
         bkpt = list_entry(entry, bwcpoint_t, list);
         if ( current->pid == bkpt->process && 
-             bkpt->type == BWC_DEBUG )
+             (bkpt->type == BWC_DEBUG ||                      /* single step */
+              bkpt->type == BWC_WATCH_STEP))  /* single step over watchpoint */
             break;
     }
     
-    if (bkpt == &bwcpoint_list || bkpt == NULL)
+    if (entry == &bwcpoint_list)
     {
         printk("not my debug  0x%x 0x%lx\n", current->pid, regs->eip);
         return 0;
     }
 
-    list_del(&bkpt->list);
-
     pdb_suspend(current);
 
-    printk("(pdb) debug  pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
+    printk("(pdb) %s  pid: %d, eip: 0x%08lx\n", 
+           bkpt->type == BWC_DEBUG ? "debug" : "watch-step",
+           current->pid, regs->eip);
 
     regs->eflags &= ~X86_EFLAGS_TF;
        set_tsk_thread_flag(current, TIF_SINGLESTEP);
 
-    resp.operation = PDB_OPCODE_STEP;
+    switch (bkpt->type)
+    {
+    case BWC_DEBUG:
+        resp.operation = PDB_OPCODE_STEP;
+        break;
+    case BWC_WATCH_STEP:
+    {
+        struct list_head *watchpoint_list;
+        bwcpoint_p watch_page = bkpt->watchpoint->parent;
+
+        switch (bkpt->watchpoint->type)
+        {
+        case BWC_WATCH_READ:
+            watchpoint_list = &watch_page->watchpt_read_list; break;
+        case BWC_WATCH_WRITE: 
+            watchpoint_list = &watch_page->watchpt_write_list; break;
+        case BWC_WATCH_ACCESS:
+            watchpoint_list = &watch_page->watchpt_access_list; break;
+        default:
+            printk("unknown type %d\n", bkpt->watchpoint->type); return 0;
+        }
+
+        resp.operation = PDB_OPCODE_WATCHPOINT;
+        list_del_init(&bkpt->watchpoint->list);
+        list_add_tail(&bkpt->watchpoint->list, watchpoint_list);
+        pdb_change_pte(current, bkpt->watchpoint, PDB_PTE_UPDATE);
+        pdb_bwc_print_list();
+        break;
+    }
+    default:
+        printk("unknown breakpoint type %d %d\n", __LINE__, bkpt->type);
+        return 0;
+    }
+
     resp.process   = current->pid;
     resp.status    = PDB_RESPONSE_OKAY;
 
     pdb_send_response(&resp);
 
+    list_del(&bkpt->list);
+    kfree(bkpt);
+
     return 1;
 }
 
 
-int
+static int
 pdb_int3_fn (struct pt_regs *regs, long error_code)
 {
     pdb_response_t resp;
     bwcpoint_p bkpt = NULL;
+    memory_t address = regs->eip - 1;
 
     struct list_head *entry;
-    list_for_each(entry, &bwcpoint_list.list)
+    list_for_each(entry, &bwcpoint_list)
     {
         bkpt = list_entry(entry, bwcpoint_t, list);
         if ( current->pid == bkpt->process && 
-             regs->eip == bkpt->address    &&
+             address == bkpt->address      &&
              bkpt->type == BWC_INT3 )
             break;
     }
     
-    if (bkpt == &bwcpoint_list || bkpt == NULL)
+    if (entry == &bwcpoint_list)
     {
-        printk("not my int3 bkpt  0x%x 0x%lx\n", current->pid, regs->eip);
+        printk("not my int3 bkpt  0x%x 0x%lx\n", current->pid, address);
         return 0;
     }
 
-    printk("(pdb) int3  pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
+    printk("(pdb) int3  pid: %d, eip: 0x%08lx\n", current->pid, address);
 
     pdb_suspend(current);
 
@@ -406,6 +791,54 @@ pdb_int3_fn (struct pt_regs *regs, long error_code)
     return 1;
 }
 
+static int
+pdb_page_fault_fn (struct pt_regs *regs, long error_code, 
+                   unsigned int condition)
+{
+    unsigned long cr2;
+    unsigned long cr3;
+    bwcpoint_p bwc;
+    bwcpoint_p watchpt;
+    bwcpoint_p bkpt;
+
+    __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
+    __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : );
+
+    bwc = pdb_search_watchpoint(current->pid, cr2);
+    if ( !bwc )
+    {
+        return 0;                                                /* not mine */
+    }
+
+    printk("page_fault cr2:%08lx err:%lx eip:%08lx\n", 
+           cr2, error_code, regs->eip);
+
+    /* disable the watchpoint */
+    watchpt = bwc->watchpoint;
+    list_del_init(&bwc->list);
+    list_add_tail(&bwc->list, &bwc->parent->watchpt_disabled_list);
+    pdb_change_pte(current, bwc, PDB_PTE_RESTORE);
+
+    /* single step the faulting instruction */
+    regs->eflags |= X86_EFLAGS_TF;
+
+    /* create a bwcpoint entry so we know what to do once we regain control */
+    _pdb_bwcpoint_alloc(bkpt);
+    if ( bkpt == NULL )  return -1;
+
+    bkpt->process    = current->pid;
+    bkpt->address    = 0;
+    bkpt->type       = BWC_WATCH_STEP;
+    bkpt->watchpoint = bwc;
+
+    /* add to head so we see it first the next time we break */
+    list_add(&bkpt->list, &bwcpoint_list);                
+
+    pdb_bwc_print_list();
+    return 1;
+}
+
+
 /*
  * Local variables:
  * mode: C
index c75b9cd64727f39d1b2f7438f9c06e5f34cfcffe..b8093f9d3f36dac68415c6db64f2c4bdfb85cda5 100644 (file)
@@ -98,6 +98,11 @@ pdb_process_request (pdb_request_t *request)
         printk("(linux) detach 0x%x\n", request->process);
         resp.status = PDB_RESPONSE_OKAY;
         break;
+    case PDB_OPCODE_RD_REG :
+        resp.u.rd_reg.reg = request->u.rd_reg.reg;
+        pdb_read_register(target, &resp.u.rd_reg);
+        resp.status = PDB_RESPONSE_OKAY;
+        break;
     case PDB_OPCODE_RD_REGS :
         pdb_read_registers(target, &resp.u.rd_regs);
         resp.status = PDB_RESPONSE_OKAY;
@@ -108,14 +113,16 @@ pdb_process_request (pdb_request_t *request)
         break;
     case PDB_OPCODE_RD_MEM :
         pdb_access_memory(target, request->u.rd_mem.address,
-                          &resp.u.rd_mem.data, request->u.rd_mem.length, 0);
+                          &resp.u.rd_mem.data, request->u.rd_mem.length, 
+                          PDB_MEM_READ);
         resp.u.rd_mem.address = request->u.rd_mem.address;
         resp.u.rd_mem.length  = request->u.rd_mem.length;
         resp.status = PDB_RESPONSE_OKAY;
         break;
     case PDB_OPCODE_WR_MEM :
         pdb_access_memory(target, request->u.wr_mem.address,
-                         &request->u.wr_mem.data, request->u.wr_mem.length, 1);
+                         &request->u.wr_mem.data, request->u.wr_mem.length, 
+                          PDB_MEM_WRITE);
         resp.status = PDB_RESPONSE_OKAY;
         break;
     case PDB_OPCODE_CONTINUE :
@@ -137,6 +144,14 @@ pdb_process_request (pdb_request_t *request)
                                      request->u.bkpt.length);
         resp.status = PDB_RESPONSE_OKAY;
         break;
+    case PDB_OPCODE_SET_WATCHPT :
+        pdb_insert_watchpoint(target, &request->u.watchpt);
+        resp.status = PDB_RESPONSE_OKAY;
+        break;
+    case PDB_OPCODE_CLR_WATCHPT :
+        pdb_remove_watchpoint(target, &request->u.watchpt);
+        resp.status = PDB_RESPONSE_OKAY;
+        break;
     default:
         printk("(pdb) unknown request operation %d\n", request->operation);
         resp.status = PDB_RESPONSE_ERROR;
@@ -249,8 +264,6 @@ pdb_initialize (void)
 
     printk("----\npdb initialize   %s %s\n", __DATE__, __TIME__);
 
-    pdb_initialize_bwcpoint();
-
     /*
     if ( xen_start_info.flags & SIF_INITDOMAIN )
         return 1;
index dfcbc4375f3e2ee7ebf65e68993599f88c2a95d9..2d30eae625624b7680e4cdfa4855f2e0ae8b492e 100644 (file)
@@ -6,6 +6,7 @@
 void pdb_initialize_bwcpoint (void);
 int pdb_suspend (struct task_struct *target);
 int pdb_resume (struct task_struct *target);
+int pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op);
 int pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op);
 int pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op);
 int pdb_read_memory (struct task_struct *target, pdb_op_rd_mem_req_p req, 
@@ -20,14 +21,14 @@ int pdb_insert_memory_breakpoint (struct task_struct *target,
                                   memory_t address, u32 length);
 int pdb_remove_memory_breakpoint (struct task_struct *target,
                                   memory_t address, u32 length);
+int pdb_insert_watchpoint (struct task_struct *target,
+                           pdb_op_watchpt_p watchpt);
+int pdb_remove_watchpoint (struct task_struct *target,
+                           pdb_op_watchpt_p watchpt);
 
 int pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
                            void *data);
 
-int pdb_debug_fn (struct pt_regs *regs, long error_code,
-                  unsigned int condition);
-int pdb_int3_fn (struct pt_regs *regs, long error_code);
-
 /* module.c */
 void pdb_send_response (pdb_response_t *response);
 
index fc95bdb47ab4cce6a43d19258b5d7394e2b8a01b..a7e679ecdfcdada29c67dd579b76bf91dfe9daf1 100644 (file)
@@ -14,20 +14,27 @@ typedef struct pdb_op_attach
 
 #define PDB_OPCODE_DETACH 3
 
-#define PDB_OPCODE_RD_REGS 4
+#define PDB_OPCODE_RD_REG 4
+typedef struct pdb_op_rd_reg
+{
+    u32 reg;
+    u32 value;
+} pdb_op_rd_reg_t, *pdb_op_rd_reg_p;
+
+#define PDB_OPCODE_RD_REGS 5
 typedef struct pdb_op_rd_regs
 {
     u32 reg[GDB_REGISTER_FRAME_SIZE];
 } pdb_op_rd_regs_t, *pdb_op_rd_regs_p;
 
-#define PDB_OPCODE_WR_REG 5
+#define PDB_OPCODE_WR_REG 6
 typedef struct pdb_op_wr_reg
 {
     u32 reg;
     u32 value;
 } pdb_op_wr_reg_t, *pdb_op_wr_reg_p;
 
-#define PDB_OPCODE_RD_MEM 6
+#define PDB_OPCODE_RD_MEM 7
 typedef struct pdb_op_rd_mem_req
 {
     u32 address;
@@ -41,7 +48,7 @@ typedef struct pdb_op_rd_mem_resp
     u8  data[1024];
 } pdb_op_rd_mem_resp_t, *pdb_op_rd_mem_resp_p;
 
-#define PDB_OPCODE_WR_MEM 7
+#define PDB_OPCODE_WR_MEM 8
 typedef struct pdb_op_wr_mem
 {
     u32 address;
@@ -49,17 +56,34 @@ typedef struct pdb_op_wr_mem
     u8  data[1024];                                             /* arbitrary */
 } pdb_op_wr_mem_t, *pdb_op_wr_mem_p;
 
-#define PDB_OPCODE_CONTINUE 8
-#define PDB_OPCODE_STEP     9
+#define PDB_OPCODE_CONTINUE 9
+#define PDB_OPCODE_STEP     10
 
-#define PDB_OPCODE_SET_BKPT 10
-#define PDB_OPCODE_CLR_BKPT 11
+#define PDB_OPCODE_SET_BKPT 11
+#define PDB_OPCODE_CLR_BKPT 12
 typedef struct pdb_op_bkpt
 {
     u32 address;
     u32 length;
 } pdb_op_bkpt_t, *pdb_op_bkpt_p;
 
+#define PDB_OPCODE_SET_WATCHPT 13
+#define PDB_OPCODE_CLR_WATCHPT 14
+#define PDB_OPCODE_WATCHPOINT  15
+typedef struct pdb_op_watchpt
+{
+#define BWC_DEBUG 1
+#define BWC_INT3  3
+#define BWC_WATCH        100                         /* pdb: watchpoint page */
+#define BWC_WATCH_STEP   101                  /* pdb: watchpoint single step */
+#define BWC_WATCH_WRITE  102
+#define BWC_WATCH_READ   103
+#define BWC_WATCH_ACCESS 104
+    u32 type;
+    u32 address;
+    u32 length;
+} pdb_op_watchpt_t, *pdb_op_watchpt_p;
+
 
 typedef struct 
 {
@@ -68,10 +92,12 @@ typedef struct
     union
     {
         pdb_op_attach_t     attach;
+        pdb_op_rd_reg_t     rd_reg;
         pdb_op_wr_reg_t     wr_reg;
         pdb_op_rd_mem_req_t rd_mem;
         pdb_op_wr_mem_t     wr_mem;
         pdb_op_bkpt_t       bkpt;
+        pdb_op_watchpt_t    watchpt;
     } u;
 } pdb_request_t, *pdb_request_p;
 
@@ -87,6 +113,7 @@ typedef struct {
     s16  status;          /* PDB_RESPONSE_???    */
     union
     {
+        pdb_op_rd_reg_t      rd_reg;
         pdb_op_rd_regs_t     rd_regs;
         pdb_op_rd_mem_resp_t rd_mem;
     } u;
@@ -95,6 +122,11 @@ typedef struct {
 
 DEFINE_RING_TYPES(pdb, pdb_request_t, pdb_response_t);
 
+
+/* from access_process_vm */
+#define PDB_MEM_READ  0
+#define PDB_MEM_WRITE 1
+
 #endif
 
 
index 031d41b9178e8798ffbe2100ec6e8f3de616662e..0efd8db53200287581ad5bef7be8209dd9364614 100644 (file)
@@ -1,7 +1,15 @@
 diff -u linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c
 --- linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c     2005-07-31 22:36:50.000000000 +0100
 +++ linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c 2005-08-01 10:57:31.000000000 +0100
-@@ -172,6 +172,7 @@
+@@ -151,6 +151,7 @@
+ /* TLB flushing */
+ EXPORT_SYMBOL(flush_tlb_page);
+ #endif
++EXPORT_SYMBOL(flush_tlb_mm);
+ #ifdef CONFIG_X86_IO_APIC
+ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
+@@ -172,6 +173,7 @@
  EXPORT_SYMBOL_GPL(unset_nmi_callback);
  
  EXPORT_SYMBOL(register_die_notifier);
index 7621eb45f6a3c2bb99cafe7c7aa3cf5e763ae9d1..934524ba0cca97c125081d36c77302479bb30982 100644 (file)
@@ -42,6 +42,54 @@ typedef struct
 
 /****************************************************************************/
 
+/*
+ * dom_read_register : context_t -> int -> int32
+ */
+value
+dom_read_register (value context, value reg)
+{
+    CAMLparam2(context, reg);
+    CAMLlocal1(result);
+
+    int my_reg = Int_val(reg);
+    cpu_user_regs_t *regs;
+    context_t ctx;
+
+    decode_context(&ctx, context);
+
+    if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
+    {
+        printf("(pdb) read registers error!\n");  fflush(stdout);
+        failwith("read registers error");
+    }
+
+    dump_regs(regs);
+
+    result = caml_alloc_tuple(16);
+
+    switch (my_reg)
+    {
+    case GDB_EAX: result = caml_copy_int32(regs->eax); break;
+    case GDB_ECX: result = caml_copy_int32(regs->ecx); break;
+    case GDB_EDX: result = caml_copy_int32(regs->edx); break;
+    case GDB_EBX: result = caml_copy_int32(regs->ebx); break;
+    case GDB_ESP: result = caml_copy_int32(regs->esp); break;
+    case GDB_EBP: result = caml_copy_int32(regs->ebp); break;
+    case GDB_ESI: result = caml_copy_int32(regs->esi); break;
+    case GDB_EDI: result = caml_copy_int32(regs->edi); break;
+    case GDB_EIP: result = caml_copy_int32(regs->eip); break;
+    case GDB_EFL: result = caml_copy_int32(regs->eflags); break;
+    case GDB_CS:  result = caml_copy_int32(regs->cs);  break;
+    case GDB_SS: result = caml_copy_int32(regs->ss); break;
+    case GDB_DS: result = caml_copy_int32(regs->ds); break;
+    case GDB_ES: result = caml_copy_int32(regs->es); break;
+    case GDB_FS: result = caml_copy_int32(regs->fs); break;
+    case GDB_GS: result = caml_copy_int32(regs->gs); break;
+    }
+
+    CAMLreturn(result);
+}
+
 /*
  * dom_read_registers : context_t -> int32
  */
index 0f911fa754458ffb5ed5508df0b518ce12f6ca53..760a18273248b6f336acf5950459c04dde92e265 100644 (file)
@@ -113,6 +113,12 @@ process_handle_response (value ring)
         case PDB_OPCODE_DETACH :
             break;
             
+        case PDB_OPCODE_RD_REG :
+        {
+            sprintf(&msg[0], "%08x", _flip(resp->u.rd_reg.value));
+            break;
+        }
+
         case PDB_OPCODE_RD_REGS :
         {
             int loop;
@@ -161,16 +167,22 @@ process_handle_response (value ring)
         }
 
         case PDB_OPCODE_SET_BKPT :
+        case PDB_OPCODE_CLR_BKPT :
+        case PDB_OPCODE_SET_WATCHPT :
+        case PDB_OPCODE_CLR_WATCHPT :
         {
             break;
         }
-        case PDB_OPCODE_CLR_BKPT :
+
+        case PDB_OPCODE_WATCHPOINT :
         {
+            sprintf(msg, "S05");
             break;
         }
 
         default :
-            printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE\n");
+            printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE %d\n",
+                   resp->operation);
             break;
         }
 
@@ -260,6 +272,32 @@ proc_pause_target (value context)
 }
 
 
+/*
+ * proc_read_register : context_t -> int -> unit
+ */
+value
+proc_read_register (value context, value reg)
+{
+    CAMLparam1(context);
+
+    pdb_request_t req;
+    context_t ctx;
+    int my_reg = Int_val(reg);
+
+    decode_context(&ctx, context);
+
+    req.operation = PDB_OPCODE_RD_REG;
+    req.process = ctx.process;
+    req.u.rd_reg.reg = my_reg;
+    req.u.rd_reg.value = 0;
+
+    send_request (ctx.ring, ctx.evtchn, &req);
+
+    CAMLreturn(Val_unit);
+}
+
+
+
 /*
  * proc_read_registers : context_t -> unit
  */
@@ -443,7 +481,7 @@ proc_step_target (value context)
 
 
 /*
- * proc_insert_memory_breakpoint : context_t -> int32 -> int list -> unit
+ * proc_insert_memory_breakpoint : context_t -> int32 -> int -> unit
  */
 value
 proc_insert_memory_breakpoint (value context, value address, value length)
@@ -466,7 +504,7 @@ proc_insert_memory_breakpoint (value context, value address, value length)
 }
 
 /*
- * proc_remove_memory_breakpoint : context_t -> int32 -> int list -> unit
+ * proc_remove_memory_breakpoint : context_t -> int32 -> int -> unit
  */
 value
 proc_remove_memory_breakpoint (value context, value address, value length)
@@ -488,6 +526,54 @@ proc_remove_memory_breakpoint (value context, value address, value length)
     CAMLreturn(Val_unit);
 }
 
+/*
+ * proc_insert_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
+ */
+value
+proc_insert_watchpoint (value context, value kind, value address, value length)
+{
+    CAMLparam3(context, address, length);
+
+    context_t ctx;
+    pdb_request_t req;
+
+    decode_context(&ctx, context);
+
+    req.operation = PDB_OPCODE_SET_WATCHPT;
+    req.process = ctx.process;
+    req.u.watchpt.type    =  Int_val(kind);
+    req.u.watchpt.address = (memory_t) Int32_val(address);
+    req.u.watchpt.length  =  Int_val(length);
+
+    send_request(ctx.ring, ctx.evtchn, &req);
+
+    CAMLreturn(Val_unit);
+}
+
+/*
+ * proc_remove_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
+ */
+value
+proc_remove_watchpoint (value context, value kind, value address, value length)
+{
+    CAMLparam3(context, address, length);
+
+    context_t ctx;
+    pdb_request_t req;
+
+    decode_context(&ctx, context);
+
+    req.operation = PDB_OPCODE_CLR_WATCHPT;
+    req.process = ctx.process;
+    req.u.watchpt.type    =  Int_val(kind);
+    req.u.watchpt.address = (memory_t) Int32_val(address);
+    req.u.watchpt.length  =  Int_val(length);
+
+    send_request(ctx.ring, ctx.evtchn, &req);
+
+    CAMLreturn(Val_unit);
+}
+
 
 /*
  * Local variables:
index 9ed26be4a6ba72e95ae50009b20c548b86b3f36a..6ea537b404b2193dd03fc3283a8d69ab1f9be100 100644 (file)
@@ -1,9 +1,9 @@
 
-PDB 0.3 
+PDB 0.3.3
 http://www.cl.cam.ac.uk/netos/pdb
 
 Alex Ho  
-June 2005
+August 2005
 
 
 This is the latest incarnation of the pervasive debugger.
@@ -79,6 +79,11 @@ Usage
 Process
 
   PDB can also debug a process running in a Linux 2.6 domain. 
+  You will need to patch the Linux 2.6 domain U tree to export some
+  additional symbols for the pdb module
+
+  % make -C linux-2.6-patches
+
   After running PDB in domain 0, insert the pdb module in dom u:
   
   % insmod linux-2.6-module/pdb.ko
@@ -87,7 +92,14 @@ Process
 
   (gdb) maint packet x context = process <domid> <pid>
 
+  Read, write, and access watchpoint should also work for processes, 
+  use the "rwatch", "watch" and "awatch" gdb commands respectively.
+
+  If you are having trouble with GDB 5.3 (i386-redhat-linux-gnu),
+  try GDB 6.3 (configured with --target=i386-linux-gnu).
+
+  
 To Do
 
-- watchpoints
+- watchpoints for domains
 - support for SMP